const {
    Category,
    User,
    Post,
    Follow,
    Comment,
    Op,
    Like,
    Cover
} = require('../db');

const asyncProcess = require('../util/asyncProcess'); //异步中间件，抛出错误统一处理

const processPost = async function (post) { //文章数据处理工具
    post.user.gender = +post.user.gender;
    post.comment_length = await Comment.count({
        where: {
            postId: post.id
        }
    });
    return post;
}

const Pagination = function (req) { //分页配置对象工厂
    if (!(this instanceof Pagination)) return new Pagination(req);
    let {
        pageSize,
        pageIndex,
    } = req.query;

    //处理分页
    pageSize = parseInt(pageSize) || 0;
    pageIndex = parseInt(pageIndex) || 1;

    if (pageSize) {
        this.limit = pageSize; //每次查询条目数
    }
    this.offset = pageSize * (pageIndex - 1); //跳过的条目数
};

const newsConstroller = {
    //获取栏目列表
    async getCategoryList(req, res) {
        let follow = [];
        if (req.userId) { //token有效
            follow.push({
                id: 0,
                name: '关注',
                is_top: 1
            });
        }

        //查询栏目表
        let data = await Category.findAll();
        data = JSON.parse(JSON.stringify(data)).map(v => {
            return {
                ...v,
                is_top: +v.is_top
            }
        });
        res.send({
            data: [...follow, ...data]
        });
    },

    //获取文章列表
    async getPostList(req, res) {
        const {
            category
        } = req.query;

        let pagination = Pagination(req);

        let where = {}; //文章查询条件
        if (+category === 0) { //关注栏目，获取关注的用户列表
            //查询关注列表
            let followData = await Follow.findAll({
                attributes: [
                    ['followUserId', 'userId']
                ],
                where: {
                    userId: req.userId,
                    has_follow: true //筛选出关注项
                }
            })

            where = {
                [Op.or]: JSON.parse(JSON.stringify(followData)) //查询条件为关注用户id
            };

        } else if (category > 0) { //其他栏目

            let categoryData = await Category.findOne({
                where: {
                    id: +category
                },
                include: {
                    model: Post,
                    attributes: ['id']
                }
            });

            where = {
                [Op.or]: JSON.parse(JSON.stringify(categoryData)).posts.map(v => {
                    return {
                        id: v.id //查询条件为文章id集合
                    }
                })
            };
        }

        // 文章查询
        let data = await Post.findAll({
            where,
            attributes: {
                exclude: ['userId']
            },
            include: [{
                    attributes: {
                        exclude: ['password']
                    },
                    model: User //文章作者
                },
                {
                    model: Category, //文章分类
                },
                {
                    model: Cover,
                    as: 'cover'
                }
            ],
            order: [
                ['id', 'DESC']
            ],
            ...pagination
        });

        data = await Promise.all(JSON.parse(JSON.stringify(data)).map(async v => processPost(v)));

        //文章总数
        let total = await Post.count({
            where
        });

        if (!data) {
            return res.status(400).send({
                statusCode: 400,
                message: '无效分类'
            });
        }

        res.send({
            data,
            total
        })
    },

    //搜索文章
    async post_search(req, res) {
        const {
            keyword
        } = req.query;

        const pagination = Pagination(req); //分页对象

        let where = {}; //查询条件

        if (keyword) { //存在关键词，则进行搜索，否则返回全部文章列表
            where = {
                [Op.or]: [{
                    content: {
                        [Op.substring]: keyword
                    }
                }, {
                    title: {
                        [Op.substring]: keyword
                    }
                }]
            };
        }

        //文章查询
        let data = await Post.findAll({
            where,
            attributes: {
                exclude: ['userId']
            },
            include: [{
                    attributes: {
                        exclude: ['password']
                    },
                    model: User //文章作者
                },
                {
                    model: Category //文章分类
                },
                {
                    model: Cover,
                    as: 'cover'
                }
            ],
            order: [
                ['id', 'DESC']
            ],
            ...pagination
        });

        data = await Promise.all(JSON.parse(JSON.stringify(data)).map(async v => processPost(v))); //文章数据处理

        //文章总数计数
        let total = await Post.count({
            where
        });

        res.send({
            data,
            total
        })

    },

    //文章详情接口
    async getPostDetail(req, res) {
        const {
            id: postId
        } = req.params;

        // 查询文章
        let data = await Post.findOne({
            where: {
                id: postId
            },
            attributes: {
                exclude: ['userId']
            },
            include: [{
                    attributes: {
                        exclude: ['password']
                    },
                    model: User //文章作者
                },
                {
                    model: Category //文章分类
                },
                {
                    model: Cover, //封面
                    as: 'cover'
                }
            ]
        });
        data = await processPost(JSON.parse(JSON.stringify(data)));

        //查询关注数据
        let followData = await Follow.findOne({
            where: {
                userId: req.userId,
                followUserId: data.user.id
            },
            attributes: ['has_follow']
        });

        let has_follow = null;
        if (followData) { //非作者用户
            has_follow = followData.has_follow;
        }

        //查询用户对文章的Like数据
        let likeData = await Like.findOne({
            where: {
                userId: req.userId,
                postId //匹配文章id
            },
            attributes: ['has_star', 'has_like'],
        })

        const {
            has_star,
            has_like
        } = likeData;

        // 文章点赞总数
        const like_length = await Like.count({
            where: {
                postId,
                has_like: true
            }
        });

        res.send({
            data: {
                ...data,
                has_star,
                has_like,
                has_follow,
                like_length
            }
        })
    },

    // 文章评论列表
    async getCommentList(req, res) {
        const {
            id: postId
        } = req.params;

        const pagination = Pagination(req);

        let data = await Comment.findAll({
            where: {
                postId
            },
            attributes: {
                exclude: ['userId', 'postId']
            },
            include: {
                model: User,
                attributes: {
                    exclude: ['password']
                }
            },
            order: [
                ['id', 'DESC']
            ],
            ...pagination
        });

        data = JSON.parse(JSON.stringify(data));

        // 遍历每条评论，查询父评论
        for (let i = 0, len = data.length; i < len; i++) {
            let pointer = data[i]; //设置探索指针
            let {
                parentId
            } = pointer;

            while (parentId) { //无父评论跳出循环
                //父评论查询
                let parent = await Comment.findOne({
                    where: {
                        id: parentId
                    },
                    attributes: {
                        exclude: ['userId', 'postId']
                    },
                    include: {
                        model: User,
                        attributes: {
                            exclude: ['password']
                        }
                    }
                });
                parent = JSON.parse(JSON.stringify(parent));
                parentId = parent.parentId; //parentId下移
                delete parent.parentId; //移除parentId
                parent.user.gender = +parent.user.gender; //修正用户性别
                pointer.parent = parent; //父评论挂载在当前评论的parent上
                pointer = parent; //指针下移
            }
            //最里层评论处理
            pointer.user.gender = +pointer.user.gender;
            delete pointer.parentId;
            pointer.parent = null;
        }

        //文章评论总数
        const total = await Comment.count({
            where: {
                postId
            }
        });
        res.send({
            data,
            total
        });
    },

};

asyncProcess(newsConstroller);

module.exports = newsConstroller;